<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>水波纹进度条</title>
    <style>
      body,
      html {
        background-color: #32373c;
        width: 100vw;
        height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
      }
      .container {
        width: 300px;
        height: 300px;
        box-shadow: 17px 17px 34px #292d31, -17px -17px 34px #3c4147;
        display: flex;
        justify-content: center;
        align-items: center;
        border-radius: 50%;
        position: relative;
      }
      .container #canvas {
        position: absolute;
      }
      .container .proNum {
        font-size: 48px;
        color: #fff;
        z-index: 1000;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <canvas id="canvas"></canvas>
      <span class="proNum">0%</span>
    </div>
    <script>
      let speed = 50;
      let Width = 300;
      let Height = 300;
      let offsetX = 0;
      let offsetY = 0;
      let offsetYRange = 1.1;
      let offsetYSpeed = 0.003;
      let progressNum = 0;
      let isDrawContainer = false;

      let canvas = document.getElementById("canvas");
      let proNum = document.querySelector(".proNum");

      let ctx = canvas.getContext("2d");
      canvas.width = Width;
      canvas.height = Height;

      function drawWave(ctx, offsetX, offsetY, waveW, waveH, color) {
        let startX = 0;
        ctx.beginPath();
        let startPos = [startX];
        for (let x = startX; x < Width; x++) {
          let y =
            (1 - offsetY) * Width +
            waveH * Math.sin((startX + x) * waveW + offsetX) +
            offsetY;
          if (startPos.length == 1) {
            startPos.push(y);
          }
          ctx.lineTo(x, y);
        }
        ctx.lineTo(Width, Height);
        ctx.lineTo(startX, Height);
        ctx.lineTo(startPos[0], startPos[1]);
        ctx.fillStyle = color;
        ctx.fill();
      }

      function draw() {
        ctx.clearRect(0, 0, Width, Height);
        offsetX += speed;
        if (!isDrawContainer) {
          drawContainer(ctx);
        }
        drawWave(ctx, offsetX, offsetY, 0.04, 6, "#82fba1");
        drawWave(ctx, offsetX + 2, offsetY - 0.02, 0.04, 8, "#1cd04b");
        if (offsetY < offsetYRange) {
          offsetY += offsetYSpeed;
          progressNum += 100 / (offsetYRange / offsetYSpeed);
          proNum.innerHTML = parseInt(progressNum) + "%";
        }
        requestAnimationFrame(draw);
      }

      function drawContainer(ctx) {
        let pointR = Width / 2, 
          lineWidth = 10, 
          circleR = pointR - lineWidth;
        ctx.lineWidth = lineWidth;
        ctx.beginPath();
        ctx.arc(pointR, pointR, circleR, 0, 2 * Math.PI);
        ctx.strokeStyle = "#000000";
        ctx.clip(); 
        isDrawContainer = true;
      }
      draw();
    </script>
  </body>
</html>